<?php

namespace App\ApiTemplates;

use Slowlyo\OwlAdmin\Support\Apis\AdminBaseApi;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use ZipArchive;

class FlowChartsApi extends AdminBaseApi
{
    // 定义请求方式为GET
    public string $method = 'get';
    
    // 定义API模板的标题
    public string $title = '获取端口流量数据';

    /**
     * 处理API请求的主要逻辑
     * 从switch_port_flow表获取流量数据
     * @return array
     */
    public function handle()
    {
        try {
            // 获取请求参数
            $params = request()->all();
            $timeRange = $params['timeRange'] ?? '24th';
            $id = $params['id'] ?? null;
            $switchId = $params['switch_id'] ?? null;
            $switchPortId = $params['switch_port_id'] ?? null;
            $dataType = $params['dataType'] ?? 1000;
            $type = $params['type'] ?? '';
            $month = $params['month'] ?? '';
            $actions = $params['actions'] ?? false;

            // 如果提供了id，并且是单端口查询，从switch_port表获取switch_id和port_index
            if ($id && $type == 'single') {
                $portInfo = DB::table('switch_port')
                    ->where('id', $id)
                    ->select(['switch_id', 'port_index', 'name'])
                    ->first();
                
                if ($portInfo) {
                    $switchId = $portInfo->switch_id;
                    $switchPortId = $portInfo->port_index;
                    $displayName = $portInfo->name;
                }
            }

            // 构建基础查询
            $baseQuery = DB::table('switch_port_flow')
                ->select([
                    'timeline_5min',
                    DB::raw('SUM(in_rates) as in_rates'),
                    DB::raw('SUM(out_rates) as out_rates'),
                    DB::raw('SUM(in_collects) as in_collects'),
                    DB::raw('SUM(out_collects) as out_collects')
                ])
                ->groupBy('timeline_5min');

            // 添加时间范围条件
            $baseQuery = $this->addTimeRangeCondition($baseQuery, $timeRange, $month, $type);

            // 存储显示名称
            $displayName = '';
            
            // 根据type处理不同的查询逻辑
            if ($type === 'group' && $id) {
                // 获取客户组关联的节点列表
                $nodeList = DB::table('customer_group')
                    ->where('id', $id)
                    ->value('node_name');

                if ($nodeList) {
                    $nodeIds = explode(',', $nodeList);
                    
                    // 获取所有节点关联的端口列表
                    $portLists = DB::table('node_management')
                        ->whereIn('id', $nodeIds)
                        ->pluck('port_list')
                        ->filter()
                        ->toArray();

                    // 合并所有端口ID
                    $allPortIds = [];
                    foreach ($portLists as $portList) {
                        $allPortIds = array_merge($allPortIds, explode(',', $portList));
                    }
                    $allPortIds = array_unique($allPortIds);

                    if (!empty($allPortIds)) {
                        // 获取所有端口的switch_id和port_index映射
                        $portMappings = DB::table('switch_port')
                            ->whereIn('id', $allPortIds)
                            ->select(['switch_id', 'port_index'])
                            ->get();

                        if ($portMappings->isNotEmpty()) {
                            // 构建查询条件
                            $baseQuery->where(function($query) use ($portMappings) {
                                foreach ($portMappings as $index => $mapping) {
                                    if ($index === 0) {
                                        $query->where(function($q) use ($mapping) {
                                            $q->where('switch_id', $mapping->switch_id)
                                              ->where('switch_port_id', $mapping->port_index);
                                        });
                                    } else {
                                        $query->orWhere(function($q) use ($mapping) {
                                            $q->where('switch_id', $mapping->switch_id)
                                              ->where('switch_port_id', $mapping->port_index);
                                        });
                                    }
                                }
                            });

                            // 获取第一个端口的信息用于显示
                            $firstMapping = $portMappings->first();
                            $switchId = $firstMapping->switch_id;
                            $switchPortId = $firstMapping->port_index;
                        }
                    }

                    // 获取客户组名称用于显示
                    $groupName = DB::table('customer_group')
                        ->where('id', $id)
                        ->value('customer_name');
                    $displayName = $groupName ? "客户组: {$groupName}" : '';
                }
            } elseif ($type === 'node' && $id) {
                // 获取节点关联的端口列表
                $portList = DB::table('node_management')
                    ->where('id', $id)
                    ->value('port_list');
                
                if ($portList) {
                    $portIds = explode(',', $portList);
                    
                    // 获取所有端口的switch_id和port_index映射
                    $portMappings = DB::table('switch_port')
                        ->whereIn('id', $portIds)
                        ->select(['switch_id', 'port_index'])
                        ->get();

                    if ($portMappings->isNotEmpty()) {
                        // 构建查询条件
                        $baseQuery->where(function($query) use ($portMappings) {
                            foreach ($portMappings as $index => $mapping) {
                                if ($index === 0) {
                                    $query->where(function($q) use ($mapping) {
                                        $q->where('switch_id', $mapping->switch_id)
                                          ->where('switch_port_id', $mapping->port_index);
                                    });
                                } else {
                                    $query->orWhere(function($q) use ($mapping) {
                                        $q->where('switch_id', $mapping->switch_id)
                                          ->where('switch_port_id', $mapping->port_index);
                                    });
                                }
                            }
                        });

                        // 获取第一个端口的信息用于显示
                        $firstMapping = $portMappings->first();
                        $switchId = $firstMapping->switch_id;
                        $switchPortId = $firstMapping->port_index;

                        // 获取节点名称用于显示
                        $nodeName = DB::table('node_management')
                            ->where('id', $id)
                            ->value('name');
                        $displayName = $nodeName ? "节点: {$nodeName}" : '';
                    }
                }
            } else {
                // 单端口查询逻辑
                if ($switchId) {
                    $baseQuery->where('switch_id', $switchId);
                }
                if ($switchPortId) {
                    $baseQuery->where('switch_port_id', $switchPortId);
                }
                
                // 获取端口名称用于显示
                $portName = DB::table('switch_port')
                    ->where('switch_id', $switchId)
                    ->where('port_index', $switchPortId)
                    ->value('name');
                $displayName = $portName ?: '';
            }

            // 获取数据并按时间戳排序
            $flowData = $baseQuery->orderBy('timeline_5min', 'asc')
                ->get()
                ->map(function ($item) {
                    return [
                        'timeline_5min' => date('Y-m-d H:i:s', $item->timeline_5min),
                        'in_rates' => $item->in_rates,
                        'out_rates' => $item->out_rates,
                        'in_collects' => $item->in_collects,
                        'out_collects' => $item->out_collects
                    ];
                });

            // 获取交换机名称
            $switchName = DB::table('switch')->where('id', $switchId)->value('name');

            // 处理批量下载
            if ($actions == 'batch_download') {
                try {
                    // 创建临时目录
                    $tempDir = storage_path('app/temp/downloads');
                    if (!file_exists($tempDir)) {
                        mkdir($tempDir, 0755, true);
                    }

                    // 生成唯一文件名
                    $timestamp = date('YmdHis');
                    $uniqueId = uniqid();
                    $baseFileName = "test_{$timestamp}_{$uniqueId}";
                    
                    // 创建测试文件
                    $testFile = $tempDir . "/{$baseFileName}.txt";
                    $testContent = "This is a test file.\nTesting ZIP functionality.\nCreated at: " . date('Y-m-d H:i:s');
                    file_put_contents($testFile, $testContent);

                    // 检查文件是否创建成功
                    if (!file_exists($testFile)) {
                        throw new \Exception("测试文件创建失败");
                    }

                    // 创建ZIP文件
                    $zipFile = $tempDir . "/{$baseFileName}.zip";
                    
                    // 使用ZipArchive类
                    $zip = new ZipArchive();
                    
                    // 打开/创建ZIP文件
                    $openResult = $zip->open($zipFile, ZipArchive::CREATE);
                    if ($openResult !== true) {
                        throw new \Exception("无法创建ZIP文件，错误代码: " . $this->getZipErrorMessage($openResult));
                    }
                    
                    // 添加文件到ZIP
                    $addResult = $zip->addFile($testFile, basename($testFile));
                    if ($addResult === false) {
                        throw new \Exception("无法添加文件到ZIP: " . $zip->getStatusString());
                    }
                    
                    // 添加字符串内容作为文件
                    $addStringResult = $zip->addFromString('string_test.txt', "这是一个从字符串创建的测试文件\n" . date('Y-m-d H:i:s'));
                    if ($addStringResult === false) {
                        throw new \Exception("无法添加字符串内容到ZIP");
                    }
                    
                    // 检查ZIP中的文件数量
                    $numFiles = $zip->numFiles;
                    if ($numFiles != 2) {
                        throw new \Exception("ZIP文件中的文件数量不正确: {$numFiles}");
                    }
                    
                    // 关闭ZIP
                    $closeResult = $zip->close();
                    if ($closeResult === false) {
                        throw new \Exception("无法关闭ZIP文件: " . $zip->getStatusString());
                    }
                    
                    // 检查ZIP文件是否创建成功
                    if (!file_exists($zipFile)) {
                        throw new \Exception("ZIP文件创建失败");
                    }
                    
                    $fileSize = filesize($zipFile);
                    if ($fileSize <= 0) {
                        throw new \Exception("ZIP文件大小异常: {$fileSize} 字节");
                    }
                    
                    // 记录文件信息以便调试
                    \Log::info("ZIP文件已创建: {$zipFile}, 大小: {$fileSize} 字节, 包含 {$numFiles} 个文件");
                    
                    // 使用Laravel的下载响应，不设置额外响应头
                    return response()->download($zipFile, basename($zipFile));
                    
                } catch (\Exception $e) {
                    // 记录错误信息
                    \Log::error('ZIP创建失败: ' . $e->getMessage());
                    return [
                        'status' => 1,
                        'msg' => '创建ZIP文件失败：' . $e->getMessage() . ' 请联系管理员。'
                    ];
                }
            }

            // 下载月95流量数据
            if($actions == 'download'){
                // 计算95值
                $inRates = $flowData->pluck('in_rates')->map(function($value) {
                    return $value * 8;  // 转换为 bits
                })->sort()->values();
                $outRates = $flowData->pluck('out_rates')->map(function($value) {
                    return $value * 8;  // 转换为 bits
                })->sort()->values();
                
                $p95Index = floor($inRates->count() * 0.95);
                $inP95 = $inRates[$p95Index] ?? 0;
                $outP95 = $outRates[$p95Index] ?? 0;

                // 构建csv文件
                $csvContent = "Title:," . ($displayName ?: '流量数据') . "\n";
                $csvContent .= "Vertical Label:,bit per second\n";
                $csvContent .= "Start Date:," . ($flowData->first()['timeline_5min'] ?? '') . "\n";
                $csvContent .= "End Date:," . ($flowData->last()['timeline_5min'] ?? '') . "\n";
                $csvContent .= "Step:,300\n";
                $csvContent .= "Total Rows:," . $flowData->count() . "\n";
                $csvContent .= "95th Percentile:,In:," . $inP95 . ",Out:," . $outP95 . "\n";
                $csvContent .= "Date,Inbound,Outbound\n";

                foreach($flowData as $item){
                    $csvContent .= $item['timeline_5min'] . ',' 
                        . ($item['in_rates'] * 8) . ',' 
                        . ($item['out_rates'] * 8) . "\n";
                }
                
                // 生成文件名
                $monthDate = $month ? date('Y-m', (int)$month) : date('Y-m');
                $fileName = ($displayName ?: '流量数据') . '_' . $monthDate . '.csv';
                
                // 设置响应头
                return response($csvContent)
                    ->header('Content-Type', 'text/csv; charset=utf-8')
                    ->header('Content-Disposition', "attachment; filename*=UTF-8''" . rawurlencode($fileName));
            }

            // 格式化返回数据
            return [
                'status' => 0,
                'msg' => '获取成功',
                'data' => [
                    'flowData' => $flowData,
                    'port_name' => $displayName,
                    'switch_name' => $switchName,
                    'time_start' => $flowData->first()['timeline_5min'] ?? '',
                    'time_end' => $flowData->last()['timeline_5min'] ?? '',
                    'dataType' => $dataType
                ],
            ];
        } catch (\Exception $e) {
            // 异常处理
            return [
                'status' => 1,
                'msg' => '获取数据失败：' . $e->getMessage()
            ];
        }
    }

    /**
     * 根据时间范围添加查询条件
     * @param $query
     * @param string $timeRange
     * @return mixed
     */
    protected function addTimeRangeCondition($query, string $timeRange, string $month, string $type)
    {
        $now = Carbon::now();

        if ($month && $type == 'node') {
            // $month传输过来是2025-05的时间戳1746028800 需要该月份所有数据
            $startTime = strtotime(date('Y-m-01', $month));
            $endTime = strtotime(date('Y-m-t', $month));
            $query->where('timeline_5min', '>=', $startTime)
                  ->where('timeline_5min', '<=', $endTime);
            return $query;
        }
        

        
        switch ($timeRange) {
            case '24th':
                $query->where('timeline_5min', '>=', $now->copy()->subHours(24)->timestamp);
                break;
            case 'today':
                $query->where('timeline_5min', '>=', $now->copy()->startOfDay()->timestamp)
                    ->where('timeline_5min', '<=', $now->copy()->endOfDay()->timestamp);
                break;
            case 'last7days':
                $query->where('timeline_5min', '>=', $now->copy()->subDays(7)->timestamp);
                break;
            case 'week':
                $query->where('timeline_5min', '>=', $now->copy()->startOfWeek()->timestamp)
                    ->where('timeline_5min', '<=', $now->copy()->endOfWeek()->timestamp);
                break;
            case 'lastweek':
                $query->where('timeline_5min', '>=', $now->copy()->subWeek()->startOfWeek()->timestamp)
                    ->where('timeline_5min', '<=', $now->copy()->subWeek()->endOfWeek()->timestamp);
                break;
            case 'month':
                $query->where('timeline_5min', '>=', $now->copy()->startOfMonth()->timestamp);
                break;
            case 'month_full':
                $query->where('timeline_5min', '>=', $now->copy()->startOfMonth()->timestamp)
                    ->where('timeline_5min', '<=', $now->copy()->endOfMonth()->timestamp);
                break;
        }

      
        return $query;
    }

    /**
     * 获取端口列表
     */
    protected function getPortList($params)
    {
        $type = $params['type'] ?? '';
        $id = $params['id'] ?? null;
        $portList = [];

        if ($type === 'node' && $id) {
            // 获取节点关联的端口列表
            $portListStr = DB::table('node_management')
                ->where('id', $id)
                ->value('port_list');
            
            if ($portListStr) {
                $portIds = explode(',', $portListStr);
                $portList = DB::table('switch_port')
                    ->whereIn('id', $portIds)
                    ->select(['id', 'name', 'switch_id', 'port_index'])
                    ->get();
            }
        }

        return $portList;
    }

    /**
     * 获取流量数据
     */
    protected function getFlowData($port, $month)
    {
        $query = DB::table('switch_port_flow')
            ->where('switch_id', $port->switch_id)
            ->where('switch_port_id', $port->port_index)
            ->select([
                'timeline_5min',
                'in_rates',
                'out_rates'
            ]);

        // 添加月份条件
        if ($month) {
            $startTime = strtotime(date('Y-m-01', (int)$month));
            $endTime = strtotime(date('Y-m-t', (int)$month));
            $query->where('timeline_5min', '>=', $startTime)
                  ->where('timeline_5min', '<=', $endTime);
        }

        return $query->orderBy('timeline_5min', 'asc')->get();
    }

    /**
     * 生成CSV内容
     */
    protected function generateCsvContent($flowData, $displayName)
    {
        // 计算95值
        $inRates = $flowData->pluck('in_rates')->map(function($value) {
            return $value * 8;
        })->sort()->values();
        $outRates = $flowData->pluck('out_rates')->map(function($value) {
            return $value * 8;
        })->sort()->values();
        
        $p95Index = floor($inRates->count() * 0.95);
        $inP95 = $inRates[$p95Index] ?? 0;
        $outP95 = $outRates[$p95Index] ?? 0;

        // 构建CSV内容
        $csvContent = "Title:," . $displayName . "\n";
        $csvContent .= "Vertical Label:,bit per second\n";
        $csvContent .= "Start Date:," . date('Y-m-d H:i:s', $flowData->first()->timeline_5min) . "\n";
        $csvContent .= "End Date:," . date('Y-m-d H:i:s', $flowData->last()->timeline_5min) . "\n";
        $csvContent .= "Step:,300\n";
        $csvContent .= "Total Rows:," . $flowData->count() . "\n";
        $csvContent .= "95th Percentile:,In:," . $inP95 . ",Out:," . $outP95 . "\n";
        $csvContent .= "Date,Inbound,Outbound\n";

        foreach($flowData as $item){
            $csvContent .= date('Y-m-d H:i:s', $item->timeline_5min) . ',' 
                . ($item->in_rates * 8) . ',' 
                . ($item->out_rates * 8) . "\n";
        }

        return $csvContent;
    }

    /**
     * 定义API参数配置
     * @return array
     */
    public function argsSchema()
    {
        return [
            amis()->SelectControl('timeRange', '时间范围')
                ->value('24th')
                ->options([
                    ['label' => '最近24小时', 'value' => '24th'],
                    ['label' => '今天', 'value' => 'today'],
                    ['label' => '最近七天', 'value' => 'last7days'],
                    ['label' => '本周', 'value' => 'week'],
                    ['label' => '上周', 'value' => 'lastweek'],
                    ['label' => '本月（截止当前）', 'value' => 'month'],
                    ['label' => '本月（完整月份）', 'value' => 'month_full'],
                ]),
            amis()->NumberControl('id', '端口ID'),
            amis()->NumberControl('switch_id', '交换机ID'),
            amis()->NumberControl('switch_port_id', '交换机端口ID'),
            amis()->NumberControl('dataType', '数据类型')->value(1000),
            amis()->TextControl('type', '类型')
        ];
    }

    /**
     * 获取ZIP错误消息
     */
    private function getZipErrorMessage($code)
    {
        $errors = [
            ZipArchive::ER_EXISTS => 'File already exists',
            ZipArchive::ER_INCONS => 'Zip archive inconsistent',
            ZipArchive::ER_INVAL => 'Invalid argument',
            ZipArchive::ER_MEMORY => 'Memory allocation failure',
            ZipArchive::ER_NOENT => 'No such file',
            ZipArchive::ER_NOZIP => 'Not a zip archive',
            ZipArchive::ER_OPEN => 'Can\'t open file',
            ZipArchive::ER_READ => 'Read error',
            ZipArchive::ER_SEEK => 'Seek error',
        ];
        
        return isset($errors[$code]) ? $errors[$code] : 'Unknown error code: ' . $code;
    }
} 